package com.fsserver.config.aspect;

import com.fsserver.common.utils.MDCTraceUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 性能监控切面
 * 用于监控关键方法的执行时间和性能指标
 * 
 * @author fsserver
 * @date 2023-03-13
 */
@Aspect
@Component
public class PerformanceMonitorAspect {
    private static final Logger log = LoggerFactory.getLogger(PerformanceMonitorAspect.class);
    
    /**
     * 慢方法阈值（毫秒）
     */
    private static final long SLOW_METHOD_THRESHOLD = 500;
    
    /**
     * 方法执行统计信息
     */
    private final ConcurrentMap<String, MethodStats> methodStatsMap = new ConcurrentHashMap<>();
    
    /**
     * 定义切点 - 数据库操作
     */
    @Pointcut("execution(* com.fsserver.core.mapper.*.*(..))")
    public void databaseOperation() {}
    
    /**
     * 定义切点 - 服务层方法
     */
    @Pointcut("execution(* com.fsserver.core.service.*.*(..))")
    public void serviceMethod() {}
    
    /**
     * 定义切点 - 外部接口调用
     */
    @Pointcut("execution(* com.fsserver.integration.*.*(..))")
    public void externalApiCall() {}
    
    /**
     * 环绕通知 - 监控数据库操作性能
     */
    @Around("databaseOperation()")
    public Object monitorDatabaseOperation(ProceedingJoinPoint joinPoint) throws Throwable {
        return monitorPerformance(joinPoint, "DB");
    }
    
    /**
     * 环绕通知 - 监控服务层方法性能
     */
    @Around("serviceMethod()")
    public Object monitorServiceMethod(ProceedingJoinPoint joinPoint) throws Throwable {
        return monitorPerformance(joinPoint, "Service");
    }
    
    /**
     * 环绕通知 - 监控外部接口调用性能
     */
    @Around("externalApiCall()")
    public Object monitorExternalApiCall(ProceedingJoinPoint joinPoint) throws Throwable {
        return monitorPerformance(joinPoint, "API");
    }
    
    /**
     * 监控方法性能
     * 
     * @param joinPoint 连接点
     * @param type 方法类型
     * @return 方法执行结果
     * @throws Throwable 异常
     */
    private Object monitorPerformance(ProceedingJoinPoint joinPoint, String type) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        String methodName = method.getDeclaringClass().getSimpleName() + "." + method.getName();
        String fullMethodName = type + ":" + methodName;
        
        // 获取或创建方法统计信息
        MethodStats stats = methodStatsMap.computeIfAbsent(fullMethodName, k -> new MethodStats());
        
        // 使用StopWatch计时
        StopWatch stopWatch = new StopWatch(fullMethodName);
        stopWatch.start();
        
        // 记录调用次数
        stats.incrementCalls();
        
        String traceId = MDCTraceUtils.getTraceId();
        String businessId = MDCTraceUtils.getBusinessId();
        
        try {
            // 执行原方法
            return joinPoint.proceed();
        } catch (Throwable e) {
            // 记录异常次数
            stats.incrementErrors();
            
            // 记录异常日志
            log.error("[性能监控] 方法执行异常 [traceId: {}, businessId: {}, method: {}]: {}", 
                    traceId, businessId, fullMethodName, e.getMessage(), e);
            
            throw e;
        } finally {
            stopWatch.stop();
            long executionTime = stopWatch.getTotalTimeMillis();
            
            // 更新统计信息
            stats.addExecutionTime(executionTime);
            
            // 记录慢方法
            if (executionTime > SLOW_METHOD_THRESHOLD) {
                log.warn("[性能监控] 慢方法 [traceId: {}, businessId: {}, method: {}, args: {}]: 执行时间 {}ms", 
                        traceId, businessId, fullMethodName, Arrays.toString(joinPoint.getArgs()), executionTime);
            }
            
            // 定期输出性能统计信息（每100次调用）
            if (stats.getCalls() % 100 == 0) {
                logPerformanceStats(fullMethodName, stats);
            }
        }
    }
    
    /**
     * 输出性能统计信息
     * 
     * @param methodName 方法名
     * @param stats 统计信息
     */
    private void logPerformanceStats(String methodName, MethodStats stats) {
        long calls = stats.getCalls();
        long errors = stats.getErrors();
        long totalTime = stats.getTotalTime();
        double avgTime = calls > 0 ? (double) totalTime / calls : 0;
        double errorRate = calls > 0 ? (double) errors / calls * 100 : 0;
        
        log.info("[性能统计] 方法: {}, 调用次数: {}, 平均执行时间: {:.2f}ms, 错误率: {:.2f}%, 总执行时间: {}ms", 
                methodName, calls, avgTime, errorRate, totalTime);
    }
    
    /**
     * 方法统计信息类
     */
    private static class MethodStats {
        private final AtomicLong calls = new AtomicLong(0);
        private final AtomicLong errors = new AtomicLong(0);
        private final AtomicLong totalTime = new AtomicLong(0);
        
        public long getCalls() {
            return calls.get();
        }
        
        public long getErrors() {
            return errors.get();
        }
        
        public long getTotalTime() {
            return totalTime.get();
        }
        
        public void incrementCalls() {
            calls.incrementAndGet();
        }
        
        public void incrementErrors() {
            errors.incrementAndGet();
        }
        
        public void addExecutionTime(long time) {
            totalTime.addAndGet(time);
        }
    }
} 